//
// Created by wanghaiwei on 2020/1/3.
//

#ifndef LIBDL_CORE_BOOST_ANY_WRAPPER_H
#define LIBDL_CORE_BOOST_ANY_WRAPPER_H

#include <boost/any.hpp>
#include <utility>
#include <LibDL/utils.h>

class any_wrapper {
public:
    using core_type = boost::any;
    core_type core;

    any_wrapper() = default;

    template<typename Type>
    any_wrapper(const Type &value) {
        core = boost::any(value);
    };

    explicit any_wrapper(core_type core) : core(std::move(core)) {};

    boost::any &get_core() noexcept {
        return core;
    }

    template<typename Type>
    Type content() const noexcept {
        if (utils::can_cast_to<Type>(core))
            return utils::try_any_cast<Type>(core);
        else
            return Type();
    }

    template<typename Type>
    Type content() noexcept {
        if (utils::can_cast_to<Type>(core))
            return utils::try_any_cast<Type>(core);
        else
            return Type();
    }

    template<typename Type>
    bool is_type() noexcept {
        return utils::can_cast_to<Type>(core);
    }

    template<typename Type>
    bool is_type() const noexcept {
        return utils::can_cast_to<Type>(core);
    }

//this is proxy for any_wrapper get content include any_wrapper
//for the swig contains the bug, when template contains self
//it will generate the type of aa::aa
#if defined(SWIG)
%proxycode %{
    //not tested
    public OrderedDict OrderedDictContent() {
        return new OrderedDict(AnyWrapperModuleJNI.OrderedDictContent(swigCPtr, this), true);
    }

    public boolean IsOrderedDict() {
        return AnyWrapperModuleJNI.IsOrderedDict(swigCPtr, this);
    }
%}
#endif

    bool empty() const noexcept(false) {
        return core.empty();
    }

    void clear() noexcept(false) {
        core.clear();
    }

    any_wrapper &swap(any_wrapper &rhs) noexcept {
        core.swap(rhs.get_core());
        return *this;
    }

    template<typename Type>
    any_wrapper &operator=(const Type &rhs) {
        boost::any(rhs).swap(core);
        return *this;
    }

    any_wrapper &operator=(any_wrapper rhs) {
        rhs.swap(*this);
        return *this;
    }
};

#endif //LIBDL_CORE_BOOST_ANY_WRAPPER_H